/*
* INSANE - Interactive Structural Analysis Environment
*
* Copyright (C) 2003-2005
* Universidade Federal de Minas Gerais
* Escola de Engenharia
* Departamento de Engenharia de Estruturas
* 
* Author's email :    insane@dees.ufmg.br
* Author's website :  http://www.dees.ufmg.br/insane
* 
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or any later version.
* 
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
* GNU General Public License for more details.
* 
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
*/
package br.ufmg.dees.insane.drivers;

import br.ufmg.dees.insane.util.IVector;
import br.ufmg.dees.insane.util.LinearEquationSystems;

/** 
 * A class defining a
 *
 * @author Fuina, Jamile & Pitangueira, Roque
 * @since March 2005
 */
public class StandardNewtonRapson implements Step {
	private Driver driver; 
	private LinearEquationSystems sel;
	private int numMaxIterations;
    private int currentIteration;
    private IVector du;
    private IVector u;
    private IVector dup;
    private IVector duq;
    private IVector referenceForce;
    private IVector externalForce;
    private IVector internalForce;
    private IVector unbalancedForce;		
    private double loadFactorTotal;
    private int numEq;
    private double tolerance;
    private IteractiveStrategy is;
    private boolean convResult;
    private byte convType;
    public static final byte FORCE = 1;
    public static final byte DISPLACEMENT = 2;
    public static final byte BOTH = 3;
    
	public StandardNewtonRapson(Driver dv, int numMaxIterations, double tolerance, byte convType ) {
		this.driver = dv;
		this.numMaxIterations = numMaxIterations;
		this.tolerance = tolerance;
		this.convType = convType;
		this.loadFactorTotal = 0.0;
		this.sel = new LinearEquationSystems();
		
		// Fiz na classe StructuralMech o metodo que devolve a carga de referencia
		// Peguei na classe model do insane	o numero de equa��es do modelo
		
		convResult = false;
	}    
	
    public IVector getReferenceDisplacement(){	
 //   	kt = driver.reducedStiffnessMatrix();			// Peguei no insane o metodo que devolve a matriz de rigidez
 //   	driver.kinematicSolver(kt,dup,referenceForce);	// Peguei na classe OnePointEq o metodo que resolve o sistema
    	dup = sel.solverX(driver.getTangentCMatrix(),referenceForce);	//Linha vai para o metodo execute									// do tipo k . d = f e coloquei na classe StructuralMech recebendo parametros
    	return dup;
    }

    public void setReferenceDisplacement(IVector referenceDisplacement){
    	dup = referenceDisplacement;
    }
	
    public int getCurrentIteration(){
    	return currentIteration;	
    }

    public void setNumMaxIterations(int numMI){
    	numMaxIterations = numMI;
    }
    
    public void getUnbalancedDisplacement(){
    	internalForce=driver.getInternalRVector();			// Pegar no insane o metodo que devolve o vetor de for�a interna
    	unbalancedForce.sub(externalForce,internalForce);	// Peguei na classe Ivector do insane o metodo que subtrai um vetor de outro
 //   	driver.kinematicSolver(kt,duq,unbalancedForce);	// Peguei na classe OnePointEq o metodo que resolve o sistema
														// do tipo k . d = f e coloquei na classe StructuralMech recebendo parametros		
    	duq = sel.solverX(driver.getTangentCMatrix(),unbalancedForce);	//Linha vai para o metodo execute	
    }
    
    public void setUnbalancedDisplacement(IVector unbalancedDisplacement){
    	duq = unbalancedDisplacement;
    }

    public void assignStepState(double lambda){
    	loadFactorTotal += lambda;
        IVector aux1 = new IVector (this.numEq);
        aux1.scale(lambda,referenceForce);
        externalForce.add(externalForce, aux1);
        IVector aux2 = new IVector (numEq);
        aux2.scale(lambda,dup);
        du.add(aux2, duq);
        u.add(u, du);    
    	driver.assignState(u);	// Peguei na classe StructuralMech do insane o metodo que atualiza os deslocamentos do modelo
    }

    public boolean getConvergence(){
    	return convResult;
    }

    public void setConvergence(){
    	Convergence conv = new Convergence(tolerance);
    	switch(convType){
    	case FORCE:	{
    			convResult = conv.checkConvergence(unbalancedForce,referenceForce);
    		}
    	case DISPLACEMENT: {
    			convResult = conv.checkConvergence(du,u);
    		}
    	case BOTH: {
    			convResult = conv.checkConvergence(unbalancedForce,referenceForce) && conv.checkConvergence(du,u);
    		}
    	}
    }
    
    public void setNumMaxInterations(int nmi){
    	numMaxIterations = nmi;
    }

    public void setDriver(Driver dv){
    	this.driver = dv;
    }
    
    public Driver getDriver( ){
    	return this.driver;
    }
    
    public void setTolerance(double tol){
    	tolerance = tol;
    }    

    public void setIteractiveStrategy(IteractiveStrategy itestr){
    	is = itestr;
    }

    public IteractiveStrategy getIteractiveStrategy( ){
    	return this.is;
    }
    public void execute(){
    	
    	// Tirei do construtor e trouxe pra ca
    	this.numEq = driver.getNumberOfEquations();	
		this.duq = new IVector(numEq);
		this.dup = new IVector(numEq);
		this.du = new IVector(numEq);
		this.u = new IVector(numEq);
        this.externalForce = new IVector(numEq);
        this.referenceForce = new IVector(numEq);
        this.internalForce= new IVector(numEq);
        this.unbalancedForce= new IVector(numEq);

        // ate aqui
        
    	this.referenceForce = driver.getRVector();
    	duq.zero();			// Peguei o metodo que inicializa todos os elementos do vetor como zero  	
    	currentIteration = 1;    			
    	for ( int j = 0; j < numMaxIterations; j++ ){
    		this.getReferenceDisplacement();
    		if ( currentIteration == 1 ){
    			this.assignStepState(is.getPredictor());
    			getUnbalancedDisplacement(); 
    		}
    		else getUnbalancedDisplacement(); 
    		assignStepState(is.getCorrector());
    		setConvergence();
    		if (convResult);
    	}
    }
}
